//
// Created by gogoqiu on 2021/10/16.
//

#include "PreferenceAdapter.h"
#include "../model/MyTagApp.h"
#include "../src/MyObj.h"
#include "../view/InputDialog.h"
#include "../../librapidsvn/include/ids.hpp"

class PreferenceAdapter::ViewHolder:public wxPanel{
private:
    //class MyObj;
    MyTagApp *myTagApp;
protected:
    int viewType;
    //wxPanel *panel;
    //no default constructor
    PreferenceView* data;
public:
    ViewHolder( MyTagApp * myTagApp, wxWindow* parent, PreferenceView *data );
    //find view
    //void findViews();
    //update
    //void update( PreferenceData* data );
    void OnInputClickItem(wxMouseEvent& event);
    void OnSwitchClickItem(wxMouseEvent& event);
};

//
PreferenceAdapter::ViewHolder::ViewHolder(MyTagApp *myTagApp, wxWindow *parent, PreferenceView* _data )
        :wxPanel( parent ), myTagApp(myTagApp), data(_data){
    if(_data->getType() == PreferenceViewType::PT_INPUT) {
        SetBackgroundColour(wxColour(0, 128, 192));
        auto *innerSizer = new wxBoxSizer(wxVERTICAL);
        //titleSizer = new wxBoxSizer(wxHORIZONTAL);
        //
        auto *titleCtrl = new wxStaticText(this, wxID_ANY, data->getTitle(),
                                           wxDefaultPosition, wxDefaultSize, 0);
        //
        innerSizer->Add(titleCtrl, 1,
                        wxALL | wxALIGN_LEFT, 10);
        //last updated value
        auto *statusCtrl = new wxStaticText(this, wxID_ANY, data->getValue(),
                                            wxDefaultPosition, wxDefaultSize, 0);
        innerSizer->Add(statusCtrl, 1,
                        wxALL | wxALIGN_CENTER_HORIZONTAL, 4);
        //callback
        data->setControl(statusCtrl);

        SetSizer(innerSizer);
        //Layout();
        //
        auto *object = new MyObj(data);
        //
        Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ViewHolder::OnInputClickItem),
                object, this);
    }else if(_data->getType() == PreferenceViewType::PT_SWITCH ) {
        SetBackgroundColour(wxColour(0, 128, 192));
        auto *innerSizer = new wxBoxSizer(wxVERTICAL);
        //titleSizer = new wxBoxSizer(wxHORIZONTAL);
        //
        auto *titleCtrl = new wxStaticText(this, wxID_ANY, data->getTitle(),
                                           wxDefaultPosition, wxDefaultSize, 0);
        //
        innerSizer->Add(titleCtrl, 1,
                        wxALL | wxALIGN_LEFT, 10);
        //last updated value
        auto *choiceCtrl = new wxCheckBox( this, wxID_ANY,
                                           data->getValue(), wxDefaultPosition, wxDefaultSize, 0 );
        if(_data->getValue().IsSameAs("true")){
            choiceCtrl->SetValue(true );
        }
        innerSizer->Add(choiceCtrl, 1,
                        wxALL | wxALIGN_CENTER_HORIZONTAL, 4);
        //callback
        data->setControl(choiceCtrl);

        SetSizer(innerSizer);
        //Layout();
        //
        auto *object = new MyObj(data);
        //
        choiceCtrl->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ViewHolder::OnSwitchClickItem),
                object, this);
    }
}

void PreferenceAdapter::ViewHolder::OnInputClickItem(wxMouseEvent &event) {
    auto *myObj = reinterpret_cast<MyObj *>(event.GetEventUserData());
    auto *preferenceView = reinterpret_cast<PreferenceView*>(myObj->data);
    //
    //InputDialog *dialog;
    if(preferenceView->getType() == PT_INPUT ) {
        //?
        auto *dialog = new InputDialog(this, preferenceView);
        if (dialog->ShowModal() == wxID_OK) {
            if (myTagApp->getPreferenceCore()->PutValue(preferenceView->getKey(),
                                                        preferenceView->getValue()) == 0 ) {
                preferenceView->getControl()->SetLabel(preferenceView->getValue());
            }
        }
    }
    //delete myObj;
}

//how to get the control point from wxMouseEvent
void PreferenceAdapter::ViewHolder::OnSwitchClickItem(wxMouseEvent &event) {
    auto *myObj = reinterpret_cast<MyObj *>(event.GetEventUserData());
    auto *preferenceView = reinterpret_cast<PreferenceView*>(myObj->data);
    auto *choiceCtrl = (wxCheckBox*)event.GetPropagatedFrom();
    if(preferenceView->getType() == PT_SWITCH ) {
        wxString curValue = preferenceView->getValue();
        if( curValue.IsSameAs("true") ){
            //choiceCtrl->SetValue(true );
            //set value to false
            if (myTagApp->getPreferenceCore()->PutValue(preferenceView->getKey(),
                                                        "false") == 0 ) {
                preferenceView->setValue("false");
                preferenceView->getControl()->SetLabel("false");
                //choiceCtrl->SetValue(false );
            }
        }else{
            //set value to true
            if (myTagApp->getPreferenceCore()->PutValue(preferenceView->getKey(),
                                                        "true") == 0 ) {
                preferenceView->setValue("true");
                preferenceView->getControl()->SetLabel( "true" );
                //choiceCtrl->SetValue(true );
            }
        }
    }
    //不加入这句，checkbox控件数据不变化true/false
    event.Skip();
    //delete myObj;
}


struct PreferenceAdapter::Item_range_inserted_package{
    int startPosition;
    int itemCount;
    vector<PreferenceView*> items;
    Item_range_inserted_package(){
        startPosition =0;
        itemCount = 0;
    }
};

//container and message bridge
//how to notify
void PreferenceAdapter::OnFrameGetItems(int startPosition, const vector<PreferenceView*>& _items ) {
    //接收到的数据
    //
    ViewHolder* baseViewHolder;
    int i = 0;
    wxWindowList list = mListBox->GetChildren();
    //wxWindowListNode *w = list.GetFirst();
    wxWindowListNode* w;
    /*
    for( i=startPosition; i<list.size(); i++ ){
        mListBox->RemoveChild( list.operator[](i) );
        //list.[i];
    }*/
    auto *panelRootBoxSizer = new wxBoxSizer(wxVERTICAL);
    //m_listbox->RemoveChild()
    for( PreferenceView* item : _items ){
        //baseViewHolder = new ViewHolder( myTagApp, parent );

        baseViewHolder = onCreateViewHolder( 0, item );
        //
        panelRootBoxSizer->Add(baseViewHolder, 0,
                               wxEXPAND|wxALL, 5);
    }
    //
    mListBox->SetSizer( panelRootBoxSizer );
    mListBox->Layout();
}

PreferenceAdapter::PreferenceAdapter(MyTagApp *myTagApp, wxWindow *frame, wxScrolledWindow *listBox) {
    this->myTagApp = myTagApp;
    this->parent = frame;
    this->mListBox = listBox;
    //items = myTagApp->getPreferenceCore()->getPreferenceViews();
}

void PreferenceAdapter::onBindViewHolder(PreferenceAdapter::ViewHolder *holder, int position) {
    //ignore
}

void PreferenceAdapter::onBindViewHolder(PreferenceAdapter::ViewHolder *holder, PreferenceView *date) {
    //ignore
}

//
PreferenceAdapter::ViewHolder *PreferenceAdapter::onCreateViewHolder(
        int viewType    //never used
        , PreferenceView * data
        ) {
    return new ViewHolder( myTagApp, parent, data );
}

void PreferenceAdapter::clearItemsWithNotify() {
    items.clear();
    notifyDataSetChanged();
}

//preferenceFrame::request
void PreferenceAdapter::setItemsWithNotify(const vector<PreferenceView *>& infos) {
    this->items.clear();
    for( PreferenceView* item: infos ){
        this->items.push_back( item );
    }
    //this->items.addAll ( infos );
    notifyDataSetChanged();
}

void PreferenceAdapter::appendItemsWithNotify(const vector<PreferenceView *>& infos) {
    int startPosition = this->items.size();
    //this->items.addAll ( infos );
    for( PreferenceView* item: infos ){
        this->items.push_back( item );
    }
    notifyItemRangeInserted ( startPosition, infos.size() );
}

////how to notify
//wxWindow, post message to it
void PreferenceAdapter::notifyDataSetChanged() {
    auto *event = new wxCommandEvent ( wxEVT_COMMAND_MENU_SELECTED, ACTION_EVENT );
    event->SetInt (ID_DATA_SET_CHANGED );
    //event->SetClientData( &items );
    auto *insertedPackage = new Item_range_inserted_package();
    insertedPackage->startPosition = 0;
    insertedPackage->itemCount = items.size();
    insertedPackage->items = items;
    event->SetClientData( insertedPackage );
    wxPostEvent ( this->parent, *event );
}

//立即更新
void PreferenceAdapter::notifyItemRangeInserted(int startPosition, int itemCount) {
    auto *event = new wxCommandEvent ( wxEVT_COMMAND_MENU_SELECTED, ACTION_EVENT );
    event->SetInt ( ID_ITEM_RANGE_INSERTED );
    Item_range_inserted_package insertedPackage;
    insertedPackage.startPosition = startPosition;
    insertedPackage.itemCount = itemCount;
    insertedPackage.items = items;
    event->SetClientData( &insertedPackage );
    wxPostEvent ( this->parent, *event );
}

//OnActionEvent
void PreferenceAdapter::OnActionEvent(wxCommandEvent &event) {
    const int token = event.GetInt();
    const long liType = event.GetExtraLong();
    void *p;
    //vector<PreferenceView*>* _items;
    Item_range_inserted_package* insertedPackage;
    //vector<PreferenceView *> v;
    switch ( token ) {
        //actually not used, not message send by the id
        case ID_DATA_SET_CHANGED:
            p = event.GetClientData();
            if ( p != nullptr ) {
                //auto *myObj = reinterpret_cast<MyObj *>(event.GetEventUserData());
                //auto *items = reinterpret_cast<vector<DataType*>>(myObj->data);
                insertedPackage = (Item_range_inserted_package*)( p );
                //_items = reinterpret_cast<vector<PreferenceView*>>( p );
                // copy the data first. This makes sure
                // the memory is released in the occurrence
                // of an exception
                //OnFrameGetItems( 0, *_items );
                if( insertedPackage!= nullptr ) {
                    OnFrameGetItems(insertedPackage->startPosition, insertedPackage->items);
                }
            }
            break;
        case ID_ITEM_RANGE_INSERTED:
            p = event.GetClientData();
            if ( p != nullptr ) {
                insertedPackage = reinterpret_cast<Item_range_inserted_package*>( event.GetEventUserData() );
                OnFrameGetItems( insertedPackage->startPosition, insertedPackage->items );
            }
            break;
    }
}
